
/*
 * Copyright (C) 2009 Archie L. Cobbs. All rights reserved.
 *
 * $Id: ArrayFieldModel.java 295 2010-01-13 21:03:17Z archie.cobbs $
 */

package org.dellroad.sidekar.schema.model;

import org.dellroad.sidekar.schema.SchemaMismatchException;

/**
 * Array schema type.
 */
public class ArrayFieldModel extends AtomicFieldModel {

    public static final String NAME = "array";

    private AtomicFieldModel elementModel;

    // Normal constructor
    public ArrayFieldModel() {
        super(NAME);
    }

    // Copy constructor
    ArrayFieldModel(ArrayFieldModel original) {
        super(original);
        this.elementModel = (AtomicFieldModel)original.elementModel.visit(new FieldDeepCopier());
    }

    /**
     * Get the type of array elements.
     */
    public AtomicFieldModel getElementModel() {
        return this.elementModel;
    }
    public void setElementModel(AtomicFieldModel elementModel) {
        this.elementModel = elementModel;
    }

    @Override
    public String getTypeDescription() {
        return (this.elementModel != null ? this.elementModel.getTypeDescription() : null) + "[]";
    }

    @Override
    public void validate(SchemaModel schema) {

        // Superclass validation
        super.validate(schema);

        // Check element is not null
        if (this.elementModel == null)
            throw new IllegalArgumentException("array field has null element type");

        // Verify array doesn't contain itself
        for (AtomicFieldModel elementModel = this.elementModel;
          elementModel instanceof ArrayFieldModel;
          elementModel = ((ArrayFieldModel)elementModel).elementModel) {
            if (elementModel == this)
                throw new IllegalArgumentException("array field contains itself: " + this);
        }

        // Validate element
        this.elementModel.validate(schema);
    }

    @Override
    public <R> R visit(FieldModelSwitch<R> sw) {
        return sw.caseArrayFieldModel(this);
    }

    @Override
    public void checkSameField(FieldModel model) {
        super.checkSameField(model);
        ArrayFieldModel that = (ArrayFieldModel)model;
        try {
            this.elementModel.checkSameField(that.elementModel);
        } catch (SchemaMismatchException e) {
            throw new SchemaMismatchException("array elements differ: " + e.getMessage(), e);
        }
    }
}

